package com.gsbelarus.gedemin.lib.sync.protocol.entity;

public class SyncProperty {

    private static final long DEFAULT_DELAY_BETWEEN_RECONNECT = 5 * 60 * 1000;
    private static final int DEFAULT_COUNT_CONNECTIONS = 5;

    private int countConnections;
    private long delayBetweenReconnect;

    public enum Type {
        ONE_BLOCK, BLOCKS
    }

    private int currentVerData;
    private String urlForMaxVer;
    private UrlForVer urlForVer;
    private Type type;

    public interface UrlForVer {
        String getUrlForVer(int ver);
    }

    private SyncProperty() {
    }

    private static abstract class SyncPropertyBuilder<T extends SyncPropertyBuilder<T>> {

        private int countConnections = DEFAULT_COUNT_CONNECTIONS;
        private long delayBetweenReconnect = DEFAULT_DELAY_BETWEEN_RECONNECT;

        protected abstract T self();

        /**
         * @param countConnections количество переподключений (в случае timeout).
         *                       <br> Default = {@link com.gsbelarus.gedemin.lib.sync.protocol.entity.SyncProperty#DEFAULT_COUNT_CONNECTIONS}
         */
        public T setCountConnections(int countConnections) {
            this.countConnections = countConnections;
            return self();
        }

        /**
         * @param delayBetweenReconnect задержка меджу переподключениями в миллисекундах (в случае timeout).
         *                              <br> Default = {@link com.gsbelarus.gedemin.lib.sync.protocol.entity.SyncProperty#DEFAULT_DELAY_BETWEEN_RECONNECT}
         */
        public T setDelayBetweenReconnect(long delayBetweenReconnect) {
            this.delayBetweenReconnect = delayBetweenReconnect;
            return self();
        }

        public SyncProperty build() {
            SyncProperty syncProperty = new SyncProperty();
            syncProperty.countConnections = this.countConnections;
            syncProperty.delayBetweenReconnect = this.delayBetweenReconnect;
            return syncProperty;
        }
    }

    public static class SyncOneBlockBuilder extends SyncPropertyBuilder<SyncOneBlockBuilder> {

        private String url;

        @Override
        protected SyncOneBlockBuilder self() {
            return this;
        }

        /**
         * @param url url в виде строки для запроса данных одним блоком
         */
        public SyncOneBlockBuilder setUrl(String url) {
            this.url = url;
            return this;
        }

        @Override
        public SyncProperty build() {
            SyncProperty syncProperty = super.build();
            syncProperty.type = Type.ONE_BLOCK;
            syncProperty.urlForVer = new UrlForVer() {
                @Override
                public String getUrlForVer(int ver) {
                    return url;
                }
            };
            return syncProperty;
        }
    }

    public static class SyncBlocksBuilder extends SyncPropertyBuilder<SyncBlocksBuilder> {

        private int currentVerData;
        private String urlForMaxVer;
        private UrlForVer urlForVer;

        @Override
        protected SyncBlocksBuilder self() {
            return this;
        }

        /**
         * @param currentVerData текущая версия данных
         */
        public SyncBlocksBuilder setCurrentVerData(int currentVerData) {
            this.currentVerData = currentVerData;
            return this;
        }

        /**
         * @param urlForMaxVer url в виде строки для запроса максимальной версии данных (максимальный номер блока)
         */
        public SyncBlocksBuilder setUrlForMaxVer(String urlForMaxVer) {
            this.urlForMaxVer = urlForMaxVer;
            return this;
        }

        /**
         * @param urlForVer url в виде строки для запроса данных определенной версии (определенного номера блока)
         */
        public SyncBlocksBuilder setUrlForVer(UrlForVer urlForVer) {
            this.urlForVer = urlForVer;
            return this;
        }

        @Override
        public SyncProperty build() {
            SyncProperty syncProperty = super.build();
            syncProperty.type = Type.BLOCKS;
            syncProperty.currentVerData = this.currentVerData;
            syncProperty.urlForVer = this.urlForVer;
            syncProperty.urlForMaxVer = this.urlForMaxVer;
            return syncProperty;
        }
    }

    public Type getType() {
        return type;
    }

    public int getCurrentVerData() {
        return currentVerData;
    }

    public String getUrlForMaxVer() {
        return urlForMaxVer;
    }

    public String getUrlStringForVer(int ver) {
        return urlForVer.getUrlForVer(ver);
    }

    public int getCountConnections() {
        return countConnections;
    }

    public long getDelayBetweenReconnect() {
        return delayBetweenReconnect;
    }

}
